package org.apache.servicecomb.samples.practise.houserush.gateway.dispatcher.handler;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpStatus;
import org.apache.servicecomb.common.rest.filter.HttpClientFilter;
import org.apache.servicecomb.core.Handler;
import org.apache.servicecomb.core.Invocation;
import org.apache.servicecomb.core.definition.MicroserviceMeta;
import org.apache.servicecomb.provider.pojo.Invoker;
import org.apache.servicecomb.samples.practise.houserush.gateway.dispatcher.config.LoginUrlConfig;
import org.apache.servicecomb.samples.practise.houserush.gateway.rpc.UserApi;
import org.apache.servicecomb.samples.practise.houserush.gateway.rpc.po.User;
import org.apache.servicecomb.swagger.invocation.AsyncResponse;
import org.apache.servicecomb.swagger.invocation.InvocationType;
import org.apache.servicecomb.swagger.invocation.exception.InvocationException;

import java.util.concurrent.CompletableFuture;

public class AuthHandler implements Handler {

    private static UserApi userApi;

    private static LoginUrlConfig loginUrlConfig = new LoginUrlConfig();

    static {
        userApi = Invoker.createProxy("login", "userApi", UserApi.class);


    }


    @Override
    public void init(MicroserviceMeta microserviceMeta, InvocationType invocationType) {

    }

    @Override
    public void handle(Invocation invocation, AsyncResponse asyncResponse) throws Exception {
        //如果不需要鉴权，执行原有的逻辑
        //请求为空 不需要鉴权
        if (invocation.getRequestEx() == null) {
            invocation.next(asyncResponse);
            return;
        }
        //获取token
        String token = invocation.getContext("Authorization");
        //获取请求过来的接口地址
        String httpMethod = invocation.getOperationMeta().getHttpMethod();
        String microserviceName = invocation.getMicroserviceName();
        String operationPath = invocation.getOperationMeta().getOperationPath();
        String requetUrl = httpMethod + " /" + microserviceName + operationPath;
        //进行对比，根据提供的白名单进行鉴权或者登录或者无效接口的处理
        //需要鉴权
        if (loginUrlConfig.getNeedLoginUrlsSet().contains(requetUrl)) {
            if (token == null) {
                asyncResponse.consumerFail(new InvocationException(HttpStatus.SC_FORBIDDEN, "forbidden", "需要进行身份验证"));
                return;
            }
            //User user = userApi.verifyToken(token);
            CompletableFuture<User> res = userApi.verifyToken(token);

            res.whenComplete((reUser, e) -> {
                if (res.isCompletedExceptionally() || reUser == null) {
                    asyncResponse.consumerFail(new InvocationException(HttpStatus.SC_FORBIDDEN, "forbidden", "鉴权失败"));
                    return;
                }
                invocation.addContext("customerId", String.valueOf(reUser.getId()));
                invocation.addContext("newAuthorization", reUser.getToken());
                try {
                    invocation.next(asyncResponse);
                } catch (Exception ex) {
                    asyncResponse.consumerFail(new InvocationException(HttpStatus.SC_FORBIDDEN, "forbidden", "鉴权失败"));
                }
            });

            //不需要鉴权
            //看是不是登录操作
        } else if (loginUrlConfig.getNoNeedLoginUrlsSet().contains(requetUrl)) {
            if ("PUT /login/users/signin".equals(requetUrl)) {
                //调用login认证微服务进行登录
                ObjectMapper Mapper = new ObjectMapper();
                User user = Mapper.readValue(invocation.getRequestEx().getBodyBytes(), User.class);
                CompletableFuture<User> res = userApi.signin(user);
                res.whenComplete((reUser, e) -> {
                    if (res.isCompletedExceptionally() || reUser == null) {
                        asyncResponse.consumerFail(new InvocationException(HttpStatus.SC_FORBIDDEN,
                                "forbidden", "登录失败"));
                        return;
                    }
                    asyncResponse.success(reUser);
                });
                //不是登录也不用校验
            } else {
                invocation.next(asyncResponse);
            }
            //没有定义的接口方法
        } else {
            asyncResponse.consumerFail(new InvocationException(HttpStatus.SC_FORBIDDEN,
                    "forbidden", "接口未定义"));
        }

    }
}
